二叉树深度和平衡二叉树的判定
二叉树的深度
对于二叉树的深度的求解,利用递归的方式求解很简单:
下面就来设计这个递归算法:
要求一个节点的高度,先求左子树的高度,然后再求解右子树的高度。 最后树的高度就是1+max(left_depth, right_depth)。 int leftLen = depth_tree(root->left); int rightLen = depth_tree(root->right); return 1 + max(leftLen, rightLen); 那么这个递归的出口是什么: (1)可以递归到1,如果一个节点不为NULL,但是这个节点的左子树为NULL, 并且右子树也为NULL,那么返回高度为1。 但是有这种情况:这个节点的左子树不为NULL,右子树为NULL,上面求leftLen和rightLen的递归还是会传入NULL。 所以这种递归的出口不可行。 (2)索性让递归的出口变成传入NULL参数,也就是说为NULL单独递归一次函数。 if(root == NULL) return 0; 就这一个出口就能解决所有的。
算法代码实现:
int depth_tree(TreeNode *root) { if(NULL == root) { return 0; } int nLeft = depth_tree(root->left); int nRight = depth_tree(root->right); return 1 + (nLeft > nRight ? nLeft : nRight); }
二叉树的最低高度
先看二叉树的最低高度的定义:从根节点都任一个叶子节点中路径最短的那个就是二叉树的最低高度。
那么这样一看,似乎可以这个设计,把最后一句话改为: return 1 + min(left, right); 但是这样是不可行的。举一个简单的例子:
上面的代码返回的结果是1,但是这棵树的最低高度是3,因为要从根到一个叶子节点的长度。所以要修改最后的返回结果,在left和right中,如果有一个为0,则返回另一个的值;当两个都不是0的时候,才返回二者中较小的那个。
所以代码实现:
int minDepth(TreeNode* root) { if(!root) { return 0; } int left = minDepth(root->left); int right = minDepth(root->right); if(!left) { return 1 + right; } else if(!right) { return 1 + left; } else { return 1 + min(left, right); } }
二叉树平衡的判定
还是用递归的想法,想判定根节点是不是平衡的,如果不是就直接返回false,如果是然后就分别去判断这个根的左子树和右子树是否都是平衡的二叉树。
代码实现:
bool IsBalance(TreeNode *root) { if(NULL == root) return true; int left = depth_tree(root->left); int right = depth_tree(root->right); if(abs(left-right) > 1) { return false; } return IsBalance(root->left) && IsBalance(root->right); }
但是现在算法的效率还是不够高,求解root的平衡性的时候,我们遍历了左子树和右子树求解子树的高度。当我们求解root孩子的平衡性的时候,还要求解root孩子左右子树的高度,有很大一部分节点重复的被遍历了。所以效率大大的降低了。
判定二叉树平衡的高效算法
前面的算法是,对于每一个节点都要去求解它的左右子树的高度,那么可以利用二叉树的后序遍历方式,当遍历到某个节点的时候,它的左子树和右子树都已经遍历完成,同时要分别带回左、右子树的高度,以便左右子树高度对比。
bool isBalance(TreeNode *root, int *depth) { if(root == NULL) { *depth = 0; return true; } int left, right; if(isBalance(root->left, &left) && isBalance(root->right, &right)) { int diff = left - right; if(diff >= -1 && diff <=1) { *depth = 1 + max(left, right); return true; } } return false; }
这里只是一个后序遍历带回高度的算法,每个节点仅仅的遍历了一次。